; if (typeof Cesium !== 'undefined')
    /**
    * @param viewer  {object} 三维对象
    * @param options {object} 初始化参数
    * @constructor
    */
    Cesium.Drawer = (function (Cesium) {

        /**
         * 绘制对象
         * @param viewer 
         * @param options 
         * @constructor
         */
        function _(viewer) {

            if (viewer && viewer instanceof Cesium.Viewer) {

                this._drawLayer = new Cesium.CustomDataSource('drawLayer');

                viewer && viewer.dataSources.add(this._drawLayer);

                this._viewer = viewer;

                this._handler = null;

                this._drawEntity = null;

                this._isDrawing = false;
            }
        }
        _.prototype = {
            /***
             * 坐标转换 84转笛卡尔
             * 
             * @param {Object} {lng,lat,alt} 地理坐标
             * 
             * @return {Object} Cartesian3 三维位置坐标
             */
            transformWGS84ToCartesian: function (position, alt) {
                if (this._viewer) {
                    return position
                        ? Cesium.Cartesian3.fromDegrees(
                            position.lng || position.lon,
                            position.lat,
                            position.alt = alt || position.alt,
                            Cesium.Ellipsoid.WGS84
                        )
                        : Cesium.Cartesian3.ZERO
                }
            },
            /***
            * 坐标数组转换 笛卡尔转84
            * 
            * @param {Array} WSG84Arr {lng,lat,alt} 地理坐标数组
            * @param {Number} alt 拔高
            * @return {Array} Cartesian3 三维位置坐标数组
            */
            transformWGS84ArrayToCartesianArray: function (WSG84Arr, alt) {
                if (this._viewer && WSG84Arr) {
                    return WSG84Arr
                        ? WSG84Arr.map(item => { return this.transformWGS84ToCartesian(item, alt) })
                        : []
                }
            },
            /***
             * 坐标转换 笛卡尔转84
             * 
             * @param {Object} Cartesian3 三维位置坐标
             * 
             * @return {Object} {lng,lat,alt} 地理坐标
             */
            transformCartesianToWGS84: function (cartesian) {
                if (this._viewer && cartesian) {
                    var ellipsoid = Cesium.Ellipsoid.WGS84
                    var cartographic = ellipsoid.cartesianToCartographic(cartesian)
                    return {
                        lng: Cesium.Math.toDegrees(cartographic.longitude),
                        lat: Cesium.Math.toDegrees(cartographic.latitude),
                        alt: cartographic.height
                    }
                }
            },
            /**
            * 坐标数组转换 笛卡尔转86
            * 
            * @param {Array} cartesianArr 三维位置坐标数组
            * 
            * @return {Array} {lng,lat,alt} 地理坐标数组
            */
            transformCartesianArrayToWGS84Array: function (cartesianArr) {
                if (this._viewer) {
                    return cartesianArr
                        ? cartesianArr.map(item => { return this.transformCartesianToWGS84(item) })
                        : []
                }
            },
            /**
             * 84坐标转弧度坐标
             * @param {Object} position wgs84
             * @return {Object} Cartographic 弧度坐标
             * 
             */
            transformWGS84ToCartographic: function (position) {
                return position
                    ? Cesium.Cartographic.fromDegrees(
                        position.lng || position.lon,
                        position.lat,
                        position.alt
                    )
                    : Cesium.Cartographic.ZERO
            },
            /**
             * 拾取位置点
             * 
             * @param {Object} px 屏幕坐标
             * 
             * @return {Object} Cartesian3 三维坐标
             */
            getCatesian3FromPX: function (px) {

                if (this._viewer && px) {
                    var picks = this._viewer.scene.drillPick(px)
                    var cartesian = null;
                    var isOn3dtiles = false, isOnTerrain = false;
                    // drillPick
                    for (let i in picks) {
                        let pick = picks[i]

                        if (pick &&
                            pick.primitive instanceof Cesium.Cesium3DTileFeature
                            || pick && pick.primitive instanceof Cesium.Cesium3DTileset
                            || pick && pick.primitive instanceof Cesium.Model) { //模型上拾取
                            isOn3dtiles = true;
                        }
                        // 3dtilset
                        if (isOn3dtiles) {
                            this._viewer.scene.pick(px) // pick
                            cartesian = this._viewer.scene.pickPosition(px);
                            if (cartesian) {
                                let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
                                if (cartographic.height < 0) cartographic.height = 0;
                                let lon = Cesium.Math.toDegrees(cartographic.longitude)
                                    , lat = Cesium.Math.toDegrees(cartographic.latitude)
                                    , height = cartographic.height;
                                cartesian = this.transformWGS84ToCartesian({ lng: lon, lat: lat, alt: height })

                            }
                        }
                    }
                    // 地形
                    let boolTerrain = this._viewer.terrainProvider instanceof Cesium.EllipsoidTerrainProvider;
                    // Terrain
                    if (!isOn3dtiles && !boolTerrain) {
                        var ray = this._viewer.scene.camera.getPickRay(px);
                        if (!ray) return null;
                        cartesian = this._viewer.scene.globe.pick(ray, this._viewer.scene);
                        isOnTerrain = true
                    }
                    // 地球
                    if (!isOn3dtiles && !isOnTerrain && boolTerrain) {

                        cartesian = this._viewer.scene.camera.pickEllipsoid(px, this._viewer.scene.globe.ellipsoid);
                    }
                    if (cartesian) {
                        let position = this.transformCartesianToWGS84(cartesian)
                        if (position.alt < 0) {
                            cartesian = this.transformWGS84ToCartesian(position, 0.1)
                        }
                        return cartesian;
                    }
                    return false;
                }

            },
            /**
             * 绘制点
             * @param {*} options {
             *  image 图片url
             *  width 图片宽度
             *  height 图片高度
             *  verticalOrigin 图片垂直对齐，默认"BOTTOM" ["CENTER", "BOTTOM", "BASELINE", "TOP"] （可选）
             *  horizontalOrigin 图片水平对齐，默认"CENTER"  ["LEFT", "RIGHT", "CENTER"] （可选）
             *  xoffset 图片水平偏移（可选）
             *  yoffset 图片垂直偏移（可选）
             *  isAgain 是否再次绘制
             *  callback({
             *      cartesian
             *      position,
             *      entity
             *  })
             * }
             */
            drawPoint: function (options = {}) {
                this.close();
                if (this._viewer && options) {
                    var _pointEntity;
                    this._handler = new Cesium.ScreenSpaceEventHandler(this._viewer.scene.canvas);
                    this._handler.setInputAction(movement => {
                        var cartesian = this.getCatesian3FromPX(movement.position);
                        _pointEntity = new Cesium.Entity({
                            position: cartesian,
                            billboard: { //图标
                                image: options.image,
                                width: options.width,
                                height: options.height,
                                verticalOrigin: options.verticalOrigin ? Cesium.VerticalOrigin[options.verticalOrigin] : Cesium.VerticalOrigin.BOTTOM,
                                horizontalOrigin: options.horizontalOrigin ? Cesium.HorizontalOrigin[options.horizontalOrigin] : Cesium.HorizontalOrigin.CENTER,
                                pixelOffset: options.offset ? new Cesium.Cartesian2(...options.offset) : undefined,
                            }
                        });
                        if (typeof options.callback === 'function') {
                            options.callback({
                                cartesian,
                                position: this.transformCartesianToWGS84(cartesian), 
                                entity: _pointEntity
                            });
                        }
                        if(!options.isAgain) {
                            this._handler.destroy()
                            this._handler = null
                        }
                        this._drawLayer.entities.add(_pointEntity)
                    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
                }
            },
            /**
             * 绘制线
             * @param {*} options {
             *  width 线宽度
             *  color 线颜色
             *  isAgain 是否再次绘制
             *  callback({
             *      cartesian
             *      position,
             *      entity
             *  })
             * } 
             */
            drawPolyline: function (options = {}) {
                this.close();
                if (this._viewer && options) {
                    var positions = [], lineObj;
                    this._drawEntity = new Cesium.Entity();
                    this._handler = new Cesium.ScreenSpaceEventHandler(this._viewer.scene.canvas);
                    // left
                    this._handler.setInputAction((movement) => {
                        this._isDrawing = true;
                        var cartesian = this.getCatesian3FromPX(movement.position);
                        if (cartesian && cartesian.x) {
                            // 解决双击重复添加点，绘制线段（重复点会被忽略）不连续bug
                            cartesian.x += Number("0.0000000" + positions.length);
                            if (positions.length == 0) {
                                positions.push(cartesian.clone());
                            }
                            positions.push(cartesian.clone());
                        }
                    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
                    // mouse
                    this._handler.setInputAction((movement) => {
                        var cartesian = this.getCatesian3FromPX(movement.endPosition);
                        if (positions.length >= 2) {
                            if (cartesian && cartesian.x) {
                                positions.pop();
                                positions.push(cartesian.clone());
                            }
                        }
                    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
                    // right
                    this._handler.setInputAction((movement) => {
                        this._isDrawing = false;
                        this._handler.destroy();
                        this._handler = null;

                        if (typeof options.callback === 'function') {
                            options.callback({
                                cartesian: positions,
                                position: this.transformCartesianArrayToWGS84Array(positions), 
                                entity: lineObj
                            });
                        }
                        if(options.isAgain) {
                            this.drawPolyline(options);
                        }
                    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

                    this._drawEntity.polyline = {
                        width: options.width || 3
                        , material: options.color ? Cesium.Color.fromCssColorString(options.color) : Cesium.Color.YELLOW.withAlpha(0.8)
                        , clampToGround: true
                    }
                    this._drawEntity.polyline.positions = new Cesium.CallbackProperty(function () {
                        return positions
                    }, false)
                    lineObj = this._drawLayer.entities.add(this._drawEntity)
                }

            },
            /**
             * 绘制面
             * @param {*} options {
             *  callback 回调函数
             *  color 填充色
             *  outlineWidth 线宽度
             *  outlineColor 线颜色
             *  isAgain 是否再次绘制
             *  callback({
             *      cartesian
             *      position,
             *      entity
             *  })
             * } 
             */
            drawPolygon: function (options = {}) {
                this.close();
                if (this._viewer && options) {

                    var positions = [], polygon = new Cesium.PolygonHierarchy(), polyObj = null;
                    this._drawEntity = new Cesium.Entity()
                    this._handler = new Cesium.ScreenSpaceEventHandler(this._viewer.scene.canvas);
                    // left
                    this._handler.setInputAction((movement) => {
                        this._isDrawing = true;
                        var cartesian = this.getCatesian3FromPX(movement.position);
                        if (cartesian && cartesian.x) {
                            // 解决双击重复添加点，绘制线段（重复点会被忽略）不连续bug
                            cartesian.x += Number("0.0000000" + positions.length);
                            if (positions.length == 0) {
                                polygon.positions.push(cartesian.clone())
                                positions.push(cartesian.clone());
                            }
                            positions.push(cartesian.clone());
                            polygon.positions.push(cartesian.clone())

                            if (!polyObj) create()
                        }
                    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
                    // mouse
                    this._handler.setInputAction((movement) => {
                        var cartesian = this.getCatesian3FromPX(movement.endPosition);
                        if (positions.length >= 2) {
                            if (cartesian && cartesian.x) {
                                positions.pop();
                                positions.push(cartesian.clone());
                                polygon.positions.pop();
                                polygon.positions.push(cartesian.clone());
                            }
                        }
                    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

                    // right
                    this._handler.setInputAction((movement) => {
                        this._isDrawing = false;
                        this._handler.destroy();

                        positions.push(positions[0]);

                        if (typeof options.callback === 'function') {
                            options.callback({
                                cartesian: positions,
                                position: this.transformCartesianArrayToWGS84Array(positions), 
                                entity: polyObj
                            });
                        }
                        if(options.isAgain) {
                            this.drawPolygon(options);
                        }
                    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

                    const create = () => {
                        this._drawEntity.polyline = {
                            width: options.outlineWidth || 3
                            , material: options.outlineColor ? Cesium.Color.fromCssColorString(options.outlineColor) : Cesium.Color.YELLOW.withAlpha(0.8)
                            , clampToGround: true
                        }

                        this._drawEntity.polyline.positions = new Cesium.CallbackProperty(function () {
                            return [...positions, positions[0]]
                        }, false)

                        this._drawEntity.polygon = {

                            hierarchy: new Cesium.CallbackProperty(function () {
                                return polygon
                            }, false),

                            material: options.color ? Cesium.Color.fromCssColorString(options.color) : Cesium.Color.WHITE.withAlpha(0.3)
                        }

                        polyObj = this._drawLayer.entities.add(this._drawEntity)
                    }
                }

            },
            // 绘制完成后返回的坐标点position转成geojson格式
            positionToGeojson(type, position) {
                let coordinates = [];
                if(type === "Point") {
                    coordinates = [position.lng, position.lat, position.alt]
                }else if(type === "LineString") {
                    coordinates = position.map(v => [v.lng, v.lat, v.alt])
                }else if(type === "Polygon") {
                    coordinates = [position.map(v => [v.lng, v.lat, v.alt])]
                };
                let geojson = {
                    type: "Feature",
                    geometry: {
                        type,
                        coordinates
                    },
                };
                return geojson;
            },
            // 获取图层
            getLayer() {
                return this._drawLayer;
            },
            // 删除单个绘制entity
            remove(entity) {
                this._drawLayer.entities.remove(entity);
            },
            // 清除
            clear() {
                this._drawLayer.entities.removeAll();
                this._handler && this._handler.destroy();
            },
            // 关闭
            close() {
                if(this._isDrawing) {
                    this._drawLayer.entities.remove(this._drawEntity);
                }
                this._handler && this._handler.destroy();
            }
            
        }
        return _
    })(Cesium);